package com.sunl.mall.ali.mq.autoconfigure.scanner.consumer;


import com.sunl.mall.common.util.CollectionUtil;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.lang.annotation.Annotation;
import java.util.*;

public class ClassPathConsumerScanner extends ClassPathBeanDefinitionScanner {
    @Setter
    private Class<? extends Annotation> annotationClass;

    public ClassPathConsumerScanner(BeanDefinitionRegistry registry) {
        super(registry, false);
    }

    /**
     * bean过滤器
     */
    public void registerFilters() {
        if (this.annotationClass != null) {
            addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
        }
    }

    /**
     * 在classpath中搜索并处理bean
     *
     * @param scanPackagePaths 需要搜索的包路径列表
     * @return Map<分组名称 ( 会被用来作为创建的bean名称 ), List < 消费者列表>>
     */
    public Map<String, List<RuntimeBeanReference>> doScanAndGet(final String... scanPackagePaths) {
        final Set<BeanDefinitionHolder> beanDefinitions = super.doScan(scanPackagePaths);
        // 组和他的临时listener bean列表（spring处理依赖关系时最终会将RuntimeBeanReference转成实际的bean对象）
        final Map<String, List<RuntimeBeanReference>> groupListenerMap = new HashMap<>();
        if (beanDefinitions.isEmpty()) {
            // 没有找到被注解的类时输出日志
            logger.warn("No " + this.annotationClass.getSimpleName() + " was found in '" + Arrays.toString(scanPackagePaths) + "' package. Please check your configuration.");
            return groupListenerMap;
        }
        return processBeanDefinitions(beanDefinitions);
    }

    /**
     * 对使用了注解的bean按注解中的group值分组，并创建临时bean
     *
     * @param beanDefinitionHolders
     * @return
     */
    private Map<String, List<RuntimeBeanReference>> processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitionHolders) {
        Map<String, List<RuntimeBeanReference>> groupListenerTmpBeanMap = new HashMap<>();
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();
            AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(beanDefinition.getMetadata()
                    .getAnnotationAttributes(annotationClass.getName()));
            if (annotationAttributes == null) {
                continue;
            }
            final String groupValue = annotationAttributes.getString("group");
            if (StringUtils.isBlank(groupValue)) {
                throw new IllegalArgumentException("BeanName[" + beanDefinitionHolder.getBeanName() + "] " + this.annotationClass.getSimpleName() + " group field must not empty");
            }
            // 查询同一个组下面的监听者列表
            List<RuntimeBeanReference> listenerList = groupListenerTmpBeanMap.get(groupValue);
            if (CollectionUtil.isEmpty(listenerList)) {
                listenerList = new ManagedList<>();
            }
            listenerList.add(new RuntimeBeanReference(beanDefinitionHolder.getBeanName()));
            groupListenerTmpBeanMap.put(groupValue, listenerList);
        }
        return groupListenerTmpBeanMap;
    }
}